package cn.gov.cbrc.east.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import cn.gov.cbrc.east.task.Job;

public class FileUtil {
	private static final Logger logger = LogManager.getLogger(FileUtil.class);
	private static int _bufferSize = 1024;
	//为找到换行符允许最大的偏移量
	private static long max_n = 1024*1024*100;
	
	/**
	 * <p>方法描述: 文件分割主任务处理(假分割，只确定校验文件的开始位置和结束位置)</p>
	 * <p>方法备注: </p>
	 * @param filePath 待处理文件位置
	 * @param truncateSize 
	 * @return
	 * <p>创建人：王川</p>
	 * <p>创建时间：Jan 8, 2016 10:27:56 AM</p>
	 *
	 */
	public static List<FileTruncate> truncateFileToTask(String filePath,long truncateSize) throws FileNotFoundException{
		//起始位置
		long startPosition = 0;
		File file = new File(filePath);
		if(!file.exists())
			throw new FileNotFoundException();
		//结束位置
		long endPosition = file.length();
		return truncateFile(filePath, startPosition, endPosition, truncateSize);
	}
	
	
	/**
	 * <p>方法描述:将主任务分割的文件进行二次分割处理(防止内存溢出) </p>
	 * <p>方法备注: </p>
	 * @param fileTruncate 主任务文件分割对象
	 * @param truncateSize 分割大小--15M(按机器性能进行分配)
	 * @return
	 * <p>创建人：王川</p>
	 * <p>创建时间：Jan 12, 2016 10:51:07 AM</p>
	 *
	 */
	public static List<FileTruncate> truncateFileToSubTask(FileTruncate fileTruncate,long truncateSize){
		//起始位置
		long startPosition = fileTruncate.get_startPosition();
		//结束位置
		long endPosition = fileTruncate.get_endPosition();
		//分割文件索引
		String filePath = fileTruncate.get_filePath();
		return truncateFile(filePath, startPosition, endPosition, truncateSize);
	}
	
	/**
	 * <p>方法描述:文件分割(虚拟分割) </p>
	 * <p>方法备注: </p>
	 * @param filePath 分割文件位置
	 * @param startPosition 起始位置
	 * @param endPosition 结束位置
	 * @param truncateSize 分割大小
	 * @return
	 * <p>创建人：王川</p>
	 * <p>创建时间：Jan 12, 2016 10:48:13 AM</p>
	 *
	 */
	public static List<FileTruncate> truncateFile(String filePath,long startPosition,long endPosition,long truncateSize){
		//分割文件索引
		int index = 1;
		RandomAccessFile accessFile = null;
		FileChannel InChannel = null;
		List<FileTruncate> list = new ArrayList<FileTruncate>();
		//读入文件位置
		long _readPosition = startPosition + truncateSize;
		try{
			//访问文件
			accessFile = new RandomAccessFile(filePath,"r");
			//如果文件大小 < 分割大小 不需分割
			if(endPosition<=truncateSize){
				FileTruncate truncate = new FileTruncate(filePath);
				truncate.set_endPosition(endPosition);
				list.add(truncate);
				return list;
			}
			//对分割文件进行校验，保证每个分割文件都是以\r\n结束[0x0D,0x0A]，默认以1024字节进行进位查找
			InChannel = accessFile.getChannel();
			ByteBuffer byteBuffer = ByteBuffer.allocate(_bufferSize);
			//为了找换行符的位移量
			long _n=0;
			while(startPosition<=endPosition){
				if(_readPosition>=endPosition){
					FileTruncate truncate = new FileTruncate(index,filePath);
					truncate.set_startPosition(startPosition);
					truncate.set_endPosition(endPosition);
					list.add(truncate);
					break;
				}
				InChannel.read(byteBuffer,_readPosition);
				byteBuffer.flip();
				int _t = 0,_f=0;
				byte _r = 0;
				for(byte _b : byteBuffer.array()){
					_t++;
					// 换行符 \r\n结束[0x0D,0x0A]
					//TODO linux换行符 处理 
					if(_b==0x0A && _r==0x0D){
						_f = 1;
						break;
					}
					_r = _b;
				}
				if(_f == 1){
					FileTruncate truncate = new FileTruncate(index,filePath);
					truncate.set_startPosition(startPosition);
					_readPosition += _t;
					truncate.set_endPosition(_readPosition);
					list.add(truncate);
					startPosition = _readPosition;
					_readPosition += truncateSize;
					index++;
					_n = 0;
				}
				else{
					//判断偏移量是否超过最大限制(一直未找到换行符)
					if(_n > max_n){//超过最大限制，仍未找到换行符，中断操作
						list.clear();
						break;
					}else{
						_n += _bufferSize;
						_readPosition += _bufferSize;
					}
				}
				byteBuffer.clear();
			}
		}catch(Exception e){
			//分割文件失败
			logger.error("分割文件失败",e);
		}finally{
			try {
				if(null != InChannel){
					InChannel.close();
				}
				if(null != accessFile){
					accessFile.close();
				}
			}
			catch (IOException e) {
				//关闭文件失败
				e.printStackTrace();
			}
		}
		return list;
	}
	
	/**
	 * <p>方法描述:删除文件 </p>
	 * <p>方法备注: </p>
	 * @param filePath
	 * <p>创建人：王川</p>
	 * <p>创建时间：Jan 14, 2016 10:59:32 AM</p>
	 *
	 */
	public static void deleteFile(String filePath){
		File file = new File(filePath);
		if(file.exists())
			file.delete();
	}
	
}
